package app;

import interfaces.iServer;
import internal.Produto;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.MulticastSocket;
import java.net.UnknownHostException;
import java.rmi.Naming;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.server.UnicastRemoteObject;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;

import BD.BDDML;

public class Server extends UnicastRemoteObject implements iServer{

	public Server() throws RemoteException, SQLException, ClassNotFoundException {
		banco = new BDDML("Estoque");
	}
	
	private static Object writeObserver = new Object();

	private static Object readObserver = new Object();

	private static BDDML banco=null;
	
	private static Integer writeBuffer = 1;
	
	private static Integer readBuffer = 0;

	private static final long serialVersionUID = 1L;
	private String service = "rmi://localhost:9000/Server";

	public  ArrayList<Produto> connect() throws RemoteException, SQLException {
		ResultSet rs = banco.Select("SELECT * FROM PRODUTOS");
		ArrayList<Produto> produtos = new ArrayList<Produto>();
		while(rs.next()){
			int cod = rs.getInt( "codigo" );
			System.out.print( "codigo = " + cod );

			String desc = rs.getString("descricao");
			System.out.print(" descricao = " + desc );

			int qtdade = rs.getInt("quantidade");
			System.out.print(" quantidade = " + qtdade );

			double preco = rs.getDouble("preco");
			System.out.println( " preco = " + preco );

			produtos.add(new Produto(cod,desc, qtdade, preco));
		}
		return produtos;
	}

	public String getService() throws RemoteException {
		return this.service;
	}

	public void insertProduto(Produto p) throws RemoteException, SQLException {
		String cmd = banco.Insert(p.getDescricao(),p.getQtdade(), p.getPreco());
		send2Group(cmd);
	}

	public void deleteProduto(Produto p) throws RemoteException, SQLException {
//		String cmd = "DELETE FROM Produtos WHERE codigo = "+p.getCod();
//		System.out.println(cmd);
//		banco.Delete("codigo = "+p.getCod());
		send2Group(banco.Delete("codigo = "+p.getCod()));
	}

	public void updateProduto(Produto p) throws RemoteException, SQLException {
		String cmd = banco.Update(p.getDescricao(), p.getQtdade(), p.getPreco(), "codigo = "+p.getCod());
		System.out.println("UpdateProduto "+cmd);
		send2Group(cmd);
	}

	public void setService(String service) throws RemoteException {
		this.service = service;	
	}
	
	public void send2Group(String msg){
		try {
			InetAddress grupo = InetAddress.getByName("224.0.0.1");
			MulticastSocket s = new MulticastSocket();
			
			DatagramPacket datagram = 
				new DatagramPacket(msg.getBytes(), msg.length(),grupo, 2000);
			
			System.out.println("==> Enviando mensagem para o grupo: " + msg );
			s.send(datagram);
			System.out.println("==> Ok. send2group Finalizou!");
			
			s.close();
			
		} catch (UnknownHostException e) {
			System.err.println("Excessao causada pelo GRUPO...");
			e.printStackTrace();
		} catch (IOException e) {
			System.err.println("Excessao causada pelo Multicast...");
			e.printStackTrace();
		} catch(Exception exc) {
			exc.printStackTrace();
		}
	}

	public void readDown() throws RemoteException, InterruptedException {
		print("readDown()");
		synchronized (readObserver){
			readBuffer--;
			readObserver.notifyAll();
		}
		print("liberei minha leitura");
	}

	public void readUp() throws RemoteException, InterruptedException {
		print("solicito leitura");
		synchronized (readObserver){
			while(writeBuffer<=0){
				writeBuffer.wait();
			};
			readBuffer++;
			print("recebi leitura");
		}
	}

	public void writeDown() throws RemoteException, InterruptedException {
		print("solicito escrita");
		synchronized (readObserver){
			while(readBuffer>0){
				readObserver.wait();
			};
			writeBuffer--;
		}
		synchronized (writeObserver){
			while(writeBuffer==0){
				writeObserver.wait();
			};
			writeBuffer--;
		}
		print("escrita recebida");
	}

	public void writeUp() throws RemoteException, InterruptedException {
		System.out.println("writeUp()");
		synchronized (writeObserver){
			writeBuffer++;
			writeObserver.notifyAll();
		}
		System.out.println("liberei minha escrita");
	}
	
	private static void print(String msg) {
		String name = Thread.currentThread().getName();
		System.out.println(name + ": " + msg);
	}
	
	public static void main(String[] args) {
		try
		{
			Server server = new Server( );
			LocateRegistry.createRegistry( 9000 );
			Naming.bind( server.getService() , server );
			System.out.println(server.getService());
			System.out.println("Server criado com sucesso!");
		}
		catch ( Exception e )
		{
			System.out.println("Probably there is already a server running or the port is busy!");
			e.printStackTrace();
		}
	}

}
